www.gusucode.com > VC++ 多声道MP3录音实时压缩保存程序-源码程序 > VC++ 多声道MP3录音实时压缩保存程序-源码程序/code/VolumeInXXX.cpp
// VolumeInXXX.cpp : Module interface implementation. // Developer : Alex Chmut // Download by http://www.NewXing.com #include "StdAfx.h" #include "VolumeInXXX.h" #pragma comment ( lib, "winmm.lib" ) ///////////////////////////////////////////////////////////////////////////// // Defines #define BAD_DWORD (DWORD)-1 #define WND_CLASS_NAME "Input Volume Msg Wnd Class" #define WND_NAME "Input Volume Msg Wnd" ///////////////////////////////////////////////////////////////////////////// // Globals PCVolumeInXXX g_pThis = NULL; //////////////////////////////////////////////////////////// //{{{ Audio specific functions #define AUDFREQ 22050 // Frequency #define AUDCHANNELS 1 // Number of channels #define AUDBITSMPL 16 // Number of bits per sample inline void SetDeviceType( WAVEFORMATEX* pwfe ) { memset( pwfe, 0, sizeof(WAVEFORMATEX) ); WORD nBlockAlign = (AUDCHANNELS*AUDBITSMPL)/8; DWORD nSamplesPerSec = AUDFREQ; pwfe->wFormatTag = WAVE_FORMAT_PCM; pwfe->nChannels = AUDCHANNELS; pwfe->nBlockAlign = nBlockAlign; pwfe->nSamplesPerSec = nSamplesPerSec; pwfe->wBitsPerSample = AUDBITSMPL; pwfe->nAvgBytesPerSec = nSamplesPerSec*nBlockAlign; } //}}} Audio specific functions ///////////////////////////////////////////////////////////////////////////// // Implementation ////////////// CVolumeInXXX::CVolumeInXXX( UINT uLineIndex, DWORD dwDeviceID/*=WAVE_MAPPER*/ ) : m_bOK(FALSE), m_bInitialized(FALSE), m_bAvailable(FALSE), m_uMixerID(0L), m_dwMixerHandle(0L), m_hWnd(NULL), m_uMicrophoneSourceLineIndex(BAD_DWORD), m_dwMinimalVolume(BAD_DWORD), m_dwMaximalVolume(BAD_DWORD), m_pfUserSink(NULL), m_dwUserValue(0L), m_dwDeviceID ( dwDeviceID ) { if ( m_bOK = Init() ) { g_pThis = this; if ( !Initialize( uLineIndex ) ) { Done(); g_pThis = NULL; } } } ////////////// CVolumeInXXX::~CVolumeInXXX() { if ( m_bOK ) Done(); g_pThis = NULL; } ////////////// BOOL CVolumeInXXX::Init() { if ( !mixerGetNumDevs() ) return FALSE; // Getting Mixer ID HWAVEIN hwaveIn; MMRESULT mmResult; WAVEFORMATEX WaveFmt; SetDeviceType( &WaveFmt ); mmResult = waveInOpen( &hwaveIn, m_dwDeviceID, &WaveFmt, 0L, 0L, CALLBACK_NULL ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: Could not open WaveIn Mapper. mmResult=%d\n", mmResult ); return FALSE; } else { mmResult = mixerGetID( (HMIXEROBJ)hwaveIn, &m_uMixerID, MIXER_OBJECTF_HWAVEIN ); waveInClose( hwaveIn ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: WaveIn Mapper in Mixer is not available. mmResult=%d\n", mmResult ); return FALSE; } } // Exposing Window to Mixer WNDCLASSEX wcx; memset( &wcx, 0, sizeof(WNDCLASSEX) ); wcx.cbSize = sizeof(WNDCLASSEX); wcx.lpszClassName = WND_CLASS_NAME; wcx.lpfnWndProc = (WNDPROC)MixerWndProc; ::RegisterClassEx(&wcx); m_hWnd = CreateWindow( WND_CLASS_NAME, WND_NAME, WS_POPUP | WS_DISABLED, 0, 0, 0, 0, NULL, NULL, NULL, NULL ); if ( !m_hWnd ) { TRACE(".InputXxxVolume: FAILURE: Could not create internal window.\n" ); return FALSE; } ::ShowWindow(m_hWnd, SW_HIDE); mmResult = mixerOpen( (LPHMIXER)&m_dwMixerHandle, m_uMixerID, (DWORD)m_hWnd, 0L, CALLBACK_WINDOW ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: Could not open Mixer. mmResult=%d\n", mmResult ); ::DestroyWindow( m_hWnd ); return FALSE; } return TRUE; } ////////////// void CVolumeInXXX::Done() { if ( mixerClose( (HMIXER)m_dwMixerHandle ) != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: WARNING: Could not close Mixer.\n" ); } ::DestroyWindow( m_hWnd ); m_bInitialized = FALSE; m_bOK = FALSE; } ////////////// void CVolumeInXXX::OnControlChanged( DWORD dwControlID ) { if ( m_dwVolumeControlID == dwControlID ) { DWORD dwVolume = GetCurrentVolume(); if ( (dwVolume!=BAD_DWORD) && (m_pfUserSink) ) { (*m_pfUserSink)( dwVolume, m_dwUserValue ); } } } ////////////// BOOL CVolumeInXXX::Initialize( UINT uLineIndex ) { MMRESULT mmResult; if ( !m_bOK ) return FALSE; TRACE(".InputXxxVolume: Initializing for the Source Line (%d) ..\n", uLineIndex ); MIXERLINE MixerLine; memset( &MixerLine, 0, sizeof(MIXERLINE) ); MixerLine.cbStruct = sizeof(MIXERLINE); MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN; mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: Could not get WaveIn Destionation Line for the requested source while initilaizing. mmResult=%d\n", mmResult ); return FALSE; } MIXERCONTROL Control; memset( &Control, 0, sizeof(MIXERCONTROL) ); Control.cbStruct = sizeof(MIXERCONTROL); MIXERLINECONTROLS LineControls; memset( &LineControls, 0, sizeof(MIXERLINECONTROLS) ); LineControls.cbStruct = sizeof(MIXERLINECONTROLS); MIXERLINE Line; memset( &Line, 0, sizeof(MIXERLINE) ); Line.cbStruct = sizeof(MIXERLINE); if ( ( uLineIndex < MixerLine.cConnections ) ) { Line.dwDestination = MixerLine.dwDestination; Line.dwSource = uLineIndex; mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: Could not get the requested Source Line while initilaizing. mmResult=%d\n", mmResult ); return FALSE; } TRACE(".InputXxxVolume: \"%s\" Source Line adopted.\n", Line.szShortName ); LineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; LineControls.dwLineID = Line.dwLineID; LineControls.cControls = 1; LineControls.cbmxctrl = sizeof(MIXERCONTROL); LineControls.pamxctrl = &Control; mmResult = mixerGetLineControls( (HMIXEROBJ)m_dwMixerHandle, &LineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE ); if ( mmResult == MMSYSERR_NOERROR ) { if ( !(Control.fdwControl & MIXERCONTROL_CONTROLF_DISABLED) ) { m_bAvailable = TRUE; TRACE(".InputXxxVolume: \"%s\" Volume control for the Source Line adopted\n", Control.szShortName ); } else { TRACE(".InputXxxVolume: WARNING: The Volume Control is disabled.\n" ); } } else { TRACE(".InputXxxVolume: WARNING: Could not get the requested Source Line Volume Control for the requested line while initilaizing. mmResult=%d\n", mmResult ); } } else { TRACE(".InputXxxVolume: FAILURE: Invalid Source Line index passed.\n" ); return FALSE; } // Retrieving Microphone Source Line for ( UINT uLine = 0; uLine < MixerLine.cConnections; uLine++ ) { MIXERLINE MicrophoneLine; memset( &MicrophoneLine, 0, sizeof(MIXERLINE) ); MicrophoneLine.cbStruct = sizeof(MIXERLINE); MicrophoneLine.dwDestination = MixerLine.dwDestination; MicrophoneLine.dwSource = uLine; mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &MicrophoneLine, MIXER_GETLINEINFOF_SOURCE ); if ( mmResult == MMSYSERR_NOERROR ) { if ( MicrophoneLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE ) { m_uMicrophoneSourceLineIndex = MicrophoneLine.dwSource; TRACE(".InputXxxVolume: Microphone Source Line \"%s\" has been found.\n", MicrophoneLine.szShortName ); break; } } } if ( m_uMicrophoneSourceLineIndex == BAD_DWORD ) { TRACE(".InputXxxVolume: WARNING: Could not retrieve Microphone Source Line.\n" ); } m_uSourceLineIndex = uLineIndex; m_nChannelCount = Line.cChannels; m_dwLineID = LineControls.dwLineID; m_dwVolumeControlID = Control.dwControlID; m_dwMinimalVolume = Control.Bounds.dwMinimum; m_dwMaximalVolume = Control.Bounds.dwMaximum; m_dwVolumeStep = Control.Metrics.cSteps; m_bInitialized = TRUE; return TRUE; } ////////////////////////////////////////////// BOOL CVolumeInXXX::GetMicrophoneSourceLineIndex( UINT* puLineIndex ) { if ( !puLineIndex || !m_bInitialized || (m_uMicrophoneSourceLineIndex==BAD_DWORD) ) return FALSE; *puLineIndex = m_uMicrophoneSourceLineIndex; return TRUE; } ////////////////////////////////////////////// // IVolume interface ////////////// BOOL CVolumeInXXX::IsAvailable() { return m_bAvailable; } ////////////// void CVolumeInXXX::Enable() { if ( !m_bInitialized || !IsAvailable() ) return; BOOL bAnyEnabled = FALSE; MMRESULT mmResult; MIXERLINE lineDestination; memset( &lineDestination, 0, sizeof(MIXERLINE) ); lineDestination.cbStruct = sizeof(MIXERLINE); lineDestination.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN; mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &lineDestination, MIXER_GETLINEINFOF_COMPONENTTYPE ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: Could not get the Destination Line while enabling. mmResult=%d\n", mmResult ); return; } // Getting all line's controls int nControlCount = lineDestination.cControls; int nChannelCount = lineDestination.cChannels; MIXERLINECONTROLS LineControls; memset( &LineControls, 0, sizeof(MIXERLINECONTROLS) ); MIXERCONTROL* aControls = (MIXERCONTROL*)malloc( nControlCount * sizeof(MIXERCONTROL) ); if ( !aControls ) { TRACE(".InputXxxVolume: FAILURE: Out of memory while enabling the line.\n" ); return; } memset( &aControls[0], 0, sizeof(nControlCount * sizeof(MIXERCONTROL)) ); for ( int i = 0; i < nControlCount; i++ ) { aControls[i].cbStruct = sizeof(MIXERCONTROL); } LineControls.cbStruct = sizeof(MIXERLINECONTROLS); LineControls.dwLineID = lineDestination.dwLineID; LineControls.cControls = nControlCount; LineControls.cbmxctrl = sizeof(MIXERCONTROL); LineControls.pamxctrl = &aControls[0]; mmResult = mixerGetLineControls( (HMIXEROBJ)m_dwMixerHandle, &LineControls, MIXER_GETLINECONTROLSF_ALL ); if ( mmResult == MMSYSERR_NOERROR ) { for ( i = 0; i < nControlCount; i++ ) { if ( aControls[i].dwControlType & MIXERCONTROL_CT_UNITS_BOOLEAN ) { MIXERCONTROLDETAILS_BOOLEAN* aDetails = NULL; int nMultipleItems = aControls[i].cMultipleItems; int nChannels = nChannelCount; // MIXERCONTROLDETAILS MIXERCONTROLDETAILS ControlDetails; memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) ); ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); ControlDetails.dwControlID = aControls[i].dwControlID; if ( aControls[i].fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) { nChannels = 1; } if ( aControls[i].fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE ) { nMultipleItems = aControls[i].cMultipleItems; aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc(nMultipleItems*nChannels*sizeof(MIXERCONTROLDETAILS_BOOLEAN)); if ( !aDetails ) { TRACE(".InputXxxVolume: FAILURE: Out of memory while enabling the line.\n" ); continue; } for ( int nItem = 0; nItem < nMultipleItems; nItem++ ) { LONG lValue = FALSE; if ( nItem == (int)m_uSourceLineIndex ) lValue = TRUE; for ( int nChannel = 0; nChannel < nChannels; nChannel++ ) { aDetails[nItem+nChannel].fValue = lValue; } } } else { nMultipleItems = 0; aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc(nChannels*sizeof(MIXERCONTROLDETAILS_BOOLEAN)); if ( !aDetails ) { TRACE(".InputXxxVolume: FAILURE: Out of memory while enabling the line.\n" ); continue; } for ( int nChannel = 0; nChannel < nChannels; nChannel++ ) { aDetails[nChannel].fValue = (LONG)TRUE; } } ControlDetails.cChannels = nChannels; ControlDetails.cMultipleItems = nMultipleItems; ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); ControlDetails.paDetails = &aDetails[0]; mmResult = mixerSetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, 0L ); if ( mmResult == MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: Enabling Line: Line control \"%s\" has been enabled.\n", aControls[i].szShortName ); bAnyEnabled = TRUE; } free( aDetails ); } } } else { TRACE(".InputXxxVolume: FAILURE: Could not get the line's controls while enabling. mmResult=%d\n", mmResult ); } free( aControls ); if ( !bAnyEnabled ) { TRACE(".InputXxxVolume: WARNING: No controls were found for enabling the line.\n" ); } } ////////////// void CVolumeInXXX::Disable() { TRACE(".InputXxxVolume: WARNING: Disable line has no sense. The function not implemented.\n" ); } ////////////// DWORD CVolumeInXXX::GetVolumeMetric() { if ( !m_bAvailable ) return BAD_DWORD; return m_dwVolumeStep; } ////////////// DWORD CVolumeInXXX::GetMinimalVolume() { if ( !m_bAvailable ) return BAD_DWORD; return m_dwMinimalVolume; } ////////////// DWORD CVolumeInXXX::GetMaximalVolume() { if ( !m_bAvailable ) return BAD_DWORD; return m_dwMaximalVolume; } ////////////// DWORD CVolumeInXXX::GetCurrentVolume() { if ( !m_bAvailable ) return BAD_DWORD; MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc(m_nChannelCount*sizeof(MIXERCONTROLDETAILS_UNSIGNED)); if ( !aDetails ) return BAD_DWORD; MIXERCONTROLDETAILS ControlDetails; memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) ); ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); ControlDetails.dwControlID = m_dwVolumeControlID; ControlDetails.cChannels = m_nChannelCount; ControlDetails.cMultipleItems = 0; ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); ControlDetails.paDetails = &aDetails[0]; MMRESULT mmResult = mixerGetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, MIXER_GETCONTROLDETAILSF_VALUE ); DWORD dw = aDetails[0].dwValue; free( aDetails ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: Could not get volume. mmResult=%d\n", mmResult ); return BAD_DWORD; } return dw; } ////////////// void CVolumeInXXX::SetCurrentVolume( DWORD dwValue ) { if ( !m_bAvailable || (dwValue<m_dwMinimalVolume) || (dwValue>m_dwMaximalVolume) ) return; MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc(m_nChannelCount*sizeof(MIXERCONTROLDETAILS_UNSIGNED)); if ( !aDetails ) return; for ( int i = 0; i < m_nChannelCount; i++ ) { aDetails[i].dwValue = dwValue; } MIXERCONTROLDETAILS ControlDetails; memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) ); ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); ControlDetails.dwControlID = m_dwVolumeControlID; ControlDetails.cChannels = m_nChannelCount; ControlDetails.cMultipleItems = 0; ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); ControlDetails.paDetails = &aDetails[0]; MMRESULT mmResult = mixerSetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, MIXER_SETCONTROLDETAILSF_VALUE ); free( aDetails ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: Could not set volume(%d) mmResult=%d\n", dwValue, mmResult ); } } ////////////// void CVolumeInXXX::RegisterNotificationSink( PONMICVOULUMECHANGE pfUserSink, DWORD dwUserValue ) { m_pfUserSink = pfUserSink; m_dwUserValue = dwUserValue; } //////////////////////////////////////////////////////////////////////// LRESULT CALLBACK CVolumeInXXX::MixerWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if ( uMsg == MM_MIXM_CONTROL_CHANGE ) { if ( g_pThis ) { g_pThis->OnControlChanged( (DWORD)lParam ); } } return ::DefWindowProc( hwnd, uMsg, wParam, lParam); } //////////////////////////////////////////////////////////////////////// BOOL CVolumeInXXX::EnumerateInputLines( DWORD dwDeviceID, PINPUTLINEPROC pUserCallback, DWORD dwUserValue ) { if ( !pUserCallback ) return FALSE; MMRESULT mmResult; HWAVEIN hwaveIn; WAVEFORMATEX WaveFmt; SetDeviceType( &WaveFmt ); mmResult = waveInOpen( &hwaveIn, dwDeviceID, &WaveFmt, 0L, 0L, CALLBACK_NULL ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: Could not open WaveIn Mapper. mmResult=%d\n", mmResult ); return FALSE; } UINT uMixerID; DWORD dwMixerHandle; mmResult = mixerGetID( (HMIXEROBJ)hwaveIn, &uMixerID, MIXER_OBJECTF_HWAVEIN ); waveInClose( hwaveIn ); if ( mmResult != MMSYSERR_NOERROR ) { TRACE(".InputXxxVolume: FAILURE: WaveIn Mapper in Mixer is not available. mmResult=%d\n", mmResult ); return FALSE; } mmResult = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L ); if ( mmResult != MMSYSERR_NOERROR ) { mixerClose( (HMIXER)dwMixerHandle ); TRACE(".InputXxxVolume: FAILURE: Could not open Mixer. mmResult=%d\n", mmResult ); return FALSE; } MIXERLINE MixerLine; memset( &MixerLine, 0, sizeof(MIXERLINE) ); MixerLine.cbStruct = sizeof(MIXERLINE); MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN; mmResult = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE ); if ( mmResult != MMSYSERR_NOERROR ) { mixerClose( (HMIXER)dwMixerHandle ); TRACE(".InputXxxVolume: FAILURE: Could not get WaveIn Destionation Line for the requested source while enumerating. mmResult=%d\n", mmResult ); return FALSE; } MIXERLINE Line; for ( UINT uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++ ) { memset( &Line, 0, sizeof(MIXERLINE) ); Line.cbStruct = sizeof(MIXERLINE); Line.dwDestination = MixerLine.dwDestination; Line.dwSource = uLineIndex; mmResult = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE ); if ( mmResult != MMSYSERR_NOERROR ) { mixerClose( (HMIXER)dwMixerHandle ); TRACE(".InputXxxVolume: FAILURE: Could not get the interated Source Line while enumerating. mmResult=%d\n", mmResult ); return FALSE; } if ( !((*pUserCallback)( uLineIndex, &Line, dwUserValue )) ) { break; } } mixerClose( (HMIXER)dwMixerHandle ); return TRUE; }